package com.jungle.mvvm.net;


import android.content.Context;

import com.jungle.mvvm.http.interceptor.BaseInterceptor;
import com.jungle.mvvm.http.interceptor.CacheInterceptor;
import com.jungle.mvvm.http.interceptor.logging.Level;
import com.jungle.mvvm.http.interceptor.logging.LoggingInterceptor;
import com.jungle.mvvm.utils.AppUtil;
import com.jungle.mvvm.utils.HttpsUtil;
import com.jungle.mvvm.utils.RxUtils;
import com.jungle.mvvm.utils.Utils;
import com.trello.rxlifecycle2.LifecycleProvider;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.Observer;
import io.reactivex.annotations.CheckReturnValue;
import io.reactivex.annotations.NonNull;
import io.reactivex.annotations.SchedulerSupport;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Cache;
import okhttp3.ConnectionPool;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.internal.platform.Platform;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * 详细说明
 *
 * @author Daniel
 * @version V1.0
 * @date 2020/12/24 16:26
 */
public abstract class BaseNetwork implements IEnvironment {
    private String baseUrl;
    private OkHttpClient okHttpClient;
    private HashMap<String, Retrofit> retrofitHashMap = new HashMap<>();
    private static EnvLevel environment;
    private Context mContext = Utils.getContext();
    private final int CACHE_TIMEOUT = 10 * 1024 * 1024;
    private final int DEFAULT_TIMEOUT = 20;
    private Cache cache = null;
    private File httpCacheDirectory;

    protected BaseNetwork() {
        if (environment == EnvLevel.TEST) {
            this.baseUrl = getTest();
        } else if (environment == EnvLevel.PROD) {
            this.baseUrl = getProd();
        } else if (environment == EnvLevel.DEV) {
            this.baseUrl = getDev();
        } else {
            this.baseUrl = getDev();
        }
    }

    /**
     * 初始化公用配置，在Application中设置
     */
    public static void init(EnvLevel env) {
        environment = env;
    }

    /**
     * 获取Retrofit
     *
     * @param service
     * @return Retrofit
     */
    protected Retrofit getRetrofit(Class service) {
        String retrofitName = baseUrl + service.getName();
        if (retrofitHashMap.get(retrofitName) != null) {
            return retrofitHashMap.get(retrofitName);
        }
        Retrofit.Builder builder = new Retrofit.Builder();
        builder.baseUrl(baseUrl);
        builder.addConverterFactory(GsonConverterFactory.create());
        builder.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
        builder.client(getOkHttpClient());
        Retrofit retrofit = builder.build();
        retrofitHashMap.put(retrofitName, retrofit);
        return retrofit;
    }

    /**
     * 设置OkHttpClient
     *
     * @return OkHttpClient
     */
    private OkHttpClient getOkHttpClient() {
        if (okHttpClient == null) {
            HttpsUtil.SSLParams sslParams = HttpsUtil.getSslSocketFactory();
            OkHttpClient.Builder builder = new OkHttpClient.Builder();

            // 设置缓存拦截器
            if (httpCacheDirectory == null) {
                httpCacheDirectory = new File(mContext.getCacheDir(), "weapon_cache");
            }
            try {
                if (cache == null) {
                    cache = new Cache(httpCacheDirectory, CACHE_TIMEOUT);
                    builder.cache(cache);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            builder.addInterceptor(new CacheInterceptor(mContext));

            // 使用BaseInterceptor设置头部
            Map<String, String> headers = new HashMap<>(4);
            headers.put("os", "android");
            headers.put("v-Code", AppUtil.getAppVersionCode() + "");
            headers.put("v-Name", AppUtil.getAppVersionName());
            headers.put("date", System.currentTimeMillis() + "");
            builder.addInterceptor(new BaseInterceptor(headers));

            if (getInterceptor() != null) {
                builder.addInterceptor(getInterceptor());
            }

            // 接口返回拦截器
            builder.addInterceptor(new ResponseInterceptor());

            // 日志拦截器
            LoggingInterceptor httpLoggingInterceptor = new LoggingInterceptor
                    //构建者模式
                    .Builder()
                    //是否开启日志打印
                    .loggable(environment != EnvLevel.PROD)
                    //打印的等级
                    .setLevel(Level.BODY)
                    // 打印类型
                    .log(Platform.INFO)
                    // request的Tag
                    .request("Request")
                    // Response的Tag
                    .response("Response")
                    //打印版本
                    .addHeader("version", AppUtil.getAppVersionName())
                    .build();
            builder.addInterceptor(httpLoggingInterceptor);

            // https处理
            builder.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager);

            builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                    .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                    // 这里你可以根据自己的机型设置同时连接的个数和时间，我这里8个，和每个保持时间为10s
                    .connectionPool(new ConnectionPool(8, 15, TimeUnit.SECONDS));
            okHttpClient = builder.build();
        }
        return okHttpClient;
    }

    /**
     * 执行
     *
     * @param lifecycleProvider
     * @param observer
     * @param <T>
     * @return
     */

    @SuppressWarnings("unchecked")
    @CheckReturnValue
    @SchedulerSupport(SchedulerSupport.NONE)
    public <T> ObservableTransformer<T, T> applySchedulers(LifecycleProvider lifecycleProvider, Observer<T> observer) {

        return upstream -> {
            if (lifecycleProvider != null) {
                upstream.compose(RxUtils.bindToLifecycle(lifecycleProvider));
            } else {
                upstream.subscribeOn(Schedulers.io());
            }
            Observable<T> observable = upstream
                    .compose(RxUtils.schedulersTransformer())
                    .compose(RxUtils.exceptionTransformer());
            observable.subscribe(observer);
            return observable;
        };
    }

    /**
     * 拦截器
     *
     * @return
     */
    protected Interceptor getInterceptor() {
        return null;
    }
}
